﻿//----------------------------------------------------------------------------------------------------
// A Visual Level is the representation of a level
//----------------------------------------------------------------------------------------------------

package HG.Visual
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.Point;
	
	import HG.Visual.VisualNode;
	
	import HG.Utilities.AStarSearch;
	
	import HG.Debug;
	
	
	public class VisualLevel extends MovieClip
	{
		var m_pointList:Array;
		var m_nodeList:Array;
		var m_connectionList:Array;
		
		var m_name:String;
		var m_gameType:Number;
		
		//----------------------------------------------------------------------------------------------------
		public function VisualLevel()
		{
			loaderInfo.addEventListener(Event.INIT, OnInit);
			
			m_pointList = new Array();
			m_nodeList = new Array();
			m_connectionList = new Array();
			
			m_name = "Untitled Level";
			m_gameType = 0;
		}
		
 		//----------------------------------------------------------------------------------------------------
		protected function OnInit(e:Event)
		{
			DrawGrid(10, 10);
		}

		//----------------------------------------------------------------------------------------------------
		public function SetName(name:String)
		{
			m_name = name;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetName():String
		{
			return m_name;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function SetGameType(gameType:Number)
		{
			m_gameType = gameType;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetGameType():Number
		{
			return m_gameType;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualAttachPoint(ID:Number)
		{
			return m_pointList[ID];
		}
		
		//----------------------------------------------------------------------------------------------------
		public function SetEditorMode(enable:Boolean)
		{
			if (enable)
			{
				this.BG.visible = true;
			}
			else
			{
				this.BG.visible = false;
			}
		}
		//----------------------------------------------------------------------------------------------------
		// Draws the grid of triangles used as the background.
		//----------------------------------------------------------------------------------------------------
		protected function DrawGrid(XSize:Number, YSize:Number)
		{
			var index:Number = 0;
			var listLength:Number = XSize * YSize;
			
			var row:Number = 0;
			var col:Number = 0;
			
			// Add boxes
			for (index = 0; index < listLength; ++index)
			{
				var attachPointID = m_pointList.length;
				var point:VisualAttachPoint = new VisualAttachPoint(attachPointID, col, row);
				BG.addChild(point);
				
				m_pointList[attachPointID] = point;
				
				col++;
				if (col > XSize)
				{
					row++;
					col = 1;
				}
				
				var colOffset = 0;
				if (row % 2 == 0)
				{
					colOffset = 128;
				}
				
				point.y = row * 217;
				point.x = (col * 256) + colOffset;
			}

			//BG.x = (1280 - BG.width) / 2;
			//BG.y = (720 - BG.height) / 2;
			
			Filler.width = BG.width;
			Filler.height = BG.height;
			
			Filler.x = 128;
			Filler.y = -100;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function ClearAll()
		{
			ClearVisualNodes();
			ClearVisualConnections();
			ClearVisualAttachPoints();
		}
		
		//----------------------------------------------------------------------------------------------------
		public function DeleteVisualObject(obj:Object)
		{
			if (obj.GetType() == "Connection")
			{
				DeleteVisualConnection(VisualConnection(obj));
			}
			else
			{
				DeleteVisualNode(VisualNode(obj));
			}
		}
		
		//----------------------------------------------------------------------------------------------------
		public function DeleteVisualNode(node:VisualNode)
		{
			Debug.ASSERT(node, "Attempt to remove bad node");
			
			var index:Number = GetVisualNodeIndex(node.GetID());
			
			if (index < 0)
				return;
			
			m_nodeList.splice(index, 1);
			
			Nodes.removeChild(node);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function ClearVisualNodes()
		{
			var index:Number = 0;
			var listLength:Number = m_nodeList.length;
			
			for (index = 0; index < listLength; ++index)
			{
				Nodes.removeChild(GetVisualNode(index));
			}
			
			m_nodeList = new Array();
		}
		
		//----------------------------------------------------------------------------------------------------
		public function AddVisualNode(typeString:String, ID:Number):VisualNode
		{
			var newNodeID:Number = ID;
			
			if (ID < 0)
				newNodeID = m_nodeList.length;
			
			var node:VisualNode = new VisualNode(typeString, newNodeID);

			m_nodeList.push(node);
			
			Nodes.addChild(node);
			
			return node;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualNodes():Array
		{
			return m_nodeList;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualNodesOcupiedByPlayer(player:Number):Array
		{
			var playerNodes:Array = new Array();
			
			var index:Number = 0;
			var listLength:Number = m_nodeList.length;
			
			for (index = 0; index < listLength; ++index)
			{
				var node:VisualNode = GetVisualNode(index);
				
				if (node.GetIsOcupiedBy(player))
					playerNodes.push(node.GetID());
			}
			
			
			return playerNodes;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualNode(ID:Number):VisualNode
		{
			var index:Number = GetVisualNodeIndex(ID);
			
			if (index < 0)
				return null;
				
			return m_nodeList[index];
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualNodeIndex(ID:Number):Number
		{
			var index:Number = 0;
			var listLength:Number = m_nodeList.length;
			
			for (index = 0; index < listLength; ++index)
			{
				if (m_nodeList[index].GetID() == ID)
					return index;
			}
			
			return -1;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function DeleteVisualConnection(con:VisualConnection)
		{
			Debug.ASSERT(con, "Attempt to remove bad connection");
			
			m_connectionList.splice(con.GetID(), 1);
			
			Connections.removeChild(con);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function ClearVisualConnections()
		{
			var index:Number = 0;
			var listLength:Number = m_connectionList.length;
			
			for (index = 0; index < listLength; ++index)
			{
				Connections.removeChild(m_connectionList[index]);
			}
			
			m_connectionList = new Array();
		}
		
		//----------------------------------------------------------------------------------------------------
		public function AddVisualConnection():VisualConnection
		{
			var newConnectionID:Number = m_connectionList.length;
			
			var con:VisualConnection = new VisualConnection(newConnectionID);
			
			m_connectionList.push(con);
			
			Connections.addChild(con);
			
			return con;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function AddVisualConnectionEx(visNodeID1:Number, visNodeID2:Number):VisualConnection
		{
			var node1:VisualNode = GetVisualNode(visNodeID1);
			var node2:VisualNode = GetVisualNode(visNodeID2);
			
			Debug.ASSERT(node1, "AddVisualConnectionEx invalid Node 1!");
			Debug.ASSERT(node2, "AddVisualConnectionEx invalid Node 2!");
			
			if (!node1 || !node2)
				return null;
		
			// create a connection, if needed
			if (!node1.GetIsConnectedTo(visNodeID2)
				&& !node2.GetIsConnectedTo(visNodeID1))
			{
				var con:VisualConnection = AddVisualConnection();
				con.SetSource(node1.GetSource(), true);
				con.SetTarget(node2.GetSource(), true);
			}
			
			// connect node 1 to 2, if needed
			if (!node1.GetIsConnectedTo(visNodeID2))
				node1.AddConnection(visNodeID2);
			
			// update connection
			var visCon:VisualConnection = GetVisualConnection(visNodeID1, visNodeID2);
			visCon.Update();
		
			return visCon;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualConnections():Array
		{
			return m_connectionList;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualConnection(fromNode:Number, toNode:Number):VisualConnection
		{

			var fromVisNode:VisualNode = GetVisualNode(fromNode);
			var toVisNode:VisualNode = GetVisualNode(toNode);
			
			Debug.ASSERT(fromVisNode, "Invalid from node!");
			Debug.ASSERT(toVisNode, "Invalid to node!");
			
			var fromVisAttach:VisualAttachPoint = fromVisNode.GetSource();
			var toVisAttach:VisualAttachPoint = toVisNode.GetSource();
			
			Debug.ASSERT(fromVisAttach, "Invalid from attach!");
			Debug.ASSERT(toVisAttach, "Invalid to attach!");
			
			var fromID:Number = fromVisAttach.GetID();
			var toID:Number = toVisAttach.GetID();
			
			var index:Number = 0;
			var listLength:Number = m_connectionList.length;
			
			for (index = 0; index < listLength; ++index)
			{
				var con:VisualConnection = m_connectionList[index];
				
				if (con.Connects(fromID, toID))
				{
					return con;
				}
			}
			
			
			return null;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualConnectionsTo(toNode:Number):Array
		{
			var connectionResults:Array = new Array();
			
			var index:Number = 0;
			var listLength:Number = m_connectionList.length;

			var toID:Number = GetVisualNode(toNode).GetSource().GetID();
			
			for (index = 0; index < listLength; ++index)
			{
				var con:VisualConnection = m_connectionList[index];
				
				if (con.ConnectsTo(toID))
				{
					connectionResults.push(con);
				}
			}
			
			return connectionResults;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetAvailableVisualConnectionsTo(playerID:Number, toID:Number):Array
		{
			var resultArray:Array = new Array();
			var connectionArray:Array = GetVisualConnectionsTo(toID);
			
			var listLength:Number = connectionArray.length;
			var index:Number = 0;
			
			for (index = 0; index < listLength; ++index)
			{
				var con:VisualConnection = connectionArray[index];
				
				var from:VisualAttachPoint = con.GetSource();
				var to:VisualAttachPoint = con.GetTarget();
					
				var fromTtargetID:Number = from.GetVisualNodeID();
				var toTargetID:Number = to.GetVisualNodeID();
				
				var fromNode:VisualNode = GetVisualNode(fromTtargetID);
				var toNode:VisualNode = GetVisualNode(toTargetID);
				
				if (fromNode.GetIsOcupiedBy(playerID) || toNode.GetIsOcupiedBy(playerID))
				{
					resultArray.push(con);
				}
			}
			
			return resultArray;
		}
		
		//----------------------------------------------------------------------------------------------------
		// WARNING: expensive. performs a path request!
		public function GetDistanceBetween(fromNodeID:Number, toNodeID:Number):Number
		{
			var path:Array = GetPathBetween(fromNodeID, toNodeID);
			
			// minus one because the path will always contain the start node.
			return (path.length - 1);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetPathBetween(fromNodeID:Number, toNodeID:Number):Array
		{
			var fromNode:VisualNode = GetVisualNode(fromNodeID);
			var toNode:VisualNode = GetVisualNode(toNodeID);
			
			var search:AStarSearch = new AStarSearch(fromNode, toNode);
			var path:Array = search.Begin();
			
			return path;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function ClearVisualAttachPoints()
		{
			var index:Number = 0;
			var listLength:Number = m_pointList.length;
			
			for (index = 0; index < listLength; ++index)
			{
				var point:VisualAttachPoint = m_pointList[index];
				
				point.SetAvailable(true);
			}
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetNearestConnectionPoints(pos:Point, isConnection:Boolean):Array
		{
			var index:Number = 0;
			var listLength:Number = m_pointList.length;
			
			var lastDist:Number = 999999;
			
			var nearestPoint:VisualAttachPoint;
			var secondNearestPoint:VisualAttachPoint;
			
			for(index = 0; index < listLength; ++index)
			{
				var point:VisualAttachPoint = m_pointList[index];
				
				Debug.ASSERT(point, "NO POINT!");
				
				// Nodes require empty points
				if (!isConnection && !point.GetAvailable())
					continue;
					
				// Connections require ocupied nodes
				if (isConnection && point.GetAvailable())
					continue;
				
				// Get Point Pos
				var pointPos:Point = new Point(point.x, point.y);
				pointPos = point.parent.localToGlobal(pointPos);
				
				//-----
				var distX = Math.abs(pos.x - pointPos.x);
				var distY = Math.abs(pos.y - pointPos.y);
				
				var dist = Math.sqrt((distX * 2) + (distY * 2));
				
				
				if (dist < lastDist)
				{
					lastDist = dist;
					secondNearestPoint = nearestPoint;
					nearestPoint = point;
				}
			}
			
			if (nearestPoint && secondNearestPoint)
			{
				return new Array(nearestPoint, secondNearestPoint);
			}
			
			return undefined;
		}
		
		//----------------------------------------------------------------------------------------------------
	}

}













